JavaScript λ°μ½λ μ΄ν°, λ©νλ°μ΄ν° λ° λ¦¬νλ μ μ νμνμ¬ κ°λ ₯ν λ°νμ λ©νλ°μ΄ν° μ‘μΈμ€λ₯Ό μ κΈ ν΄μ νκ³ μ ν리μΌμ΄μ μμ κ³ κΈ κΈ°λ₯, ν₯μλ μ μ§ κ΄λ¦¬μ± λ° λ ν° μ μ°μ±μ ꡬννμμμ€.
JavaScript λ°μ½λ μ΄ν°, λ©νλ°μ΄ν° λ° λ¦¬νλ μ : ν₯μλ κΈ°λ₯μ μν λ°νμ λ©νλ°μ΄ν° μ‘μΈμ€
μ΄κΈ° μ€ν¬λ¦½ν μν μ λμ΄ μ§νν JavaScriptλ μ΄μ 볡μ‘ν μΉ μ ν리μΌμ΄μ κ³Ό μλ² μΈ‘ νκ²½μ κΈ°λ°μ΄ λ©λλ€. μ΄λ¬ν μ§νλ 볡μ‘μ±μ κ΄λ¦¬νκ³ , μ μ§ κ΄λ¦¬μ±μ ν₯μνλ©°, μ½λ μ¬μ¬μ©μ±μ μ΄μ§νκΈ° μν κ³ κΈ νλ‘κ·Έλλ° κΈ°μ μ νμλ‘ ν©λλ€. μ€ν μ΄μ§ 2 ECMAScript μ μμΈ λ°μ½λ μ΄ν°λ λ©νλ°μ΄ν° 리νλ μ κ³Ό κ²°ν©νμ¬ λ°νμ λ©νλ°μ΄ν° μ‘μΈμ€μ Aspect-Oriented Programming(AOP) ν¨λ¬λ€μμ κ°λ₯νκ² ν¨μΌλ‘μ¨ μ΄λ¬ν λͺ©νλ₯Ό λ¬μ±νκΈ° μν κ°λ ₯ν λ©μ»€λμ¦μ μ 곡ν©λλ€.
λ°μ½λ μ΄ν° μ΄ν΄νκΈ°
λ°μ½λ μ΄ν°λ ν΄λμ€, λ©μλ, μμ± λλ λ§€κ°λ³μμ λμμ μμ νκ±°λ νμ₯νλ κ°κ²°νκ³ μ μΈμ μΈ λ°©λ²μ μ 곡νλ μΌμ’
μ λ¬Έλ²μ μ€νμ
λλ€. @ κΈ°νΈλ‘ μ λμ¬κ° λΆκ³ κΎΈλ° μμ λ°λ‘ μμ λ°°μΉλλ ν¨μμ
λλ€. μ΄λ₯Ό ν΅ν΄ λ°μ½λ μ΄ν°κ° λΆμ μμμ ν΅μ¬ λ‘μ§μ μ§μ μμ νμ§ μκ³ λ λ‘κΉ
, μ ν¨μ± κ²μ¬ λλ κΆν λΆμ¬μ κ°μ κ΅μ°¨ κ΄μ¬μ¬(cross-cutting concerns)λ₯Ό μΆκ°ν μ μμ΅λλ€.
κ°λ¨ν μλ₯Ό μκ°ν΄ λ΄
μλ€. νΉμ λ©μλκ° νΈμΆλ λλ§λ€ λ‘κΉ
ν΄μΌ νλ€κ³ κ°μ ν΄ λ³΄κ² μ΅λλ€. λ°μ½λ μ΄ν°κ° μμΌλ©΄ κ° λ©μλμ λ‘κΉ
λ‘μ§μ μλμΌλ‘ μΆκ°ν΄μΌ ν©λλ€. λ°μ½λ μ΄ν°λ₯Ό μ¬μ©νλ©΄ @log λ°μ½λ μ΄ν°λ₯Ό μμ±νκ³ λ‘κΉ
νλ €λ λ©μλμ μ μ©ν μ μμ΅λλ€. μ΄ μ κ·Ό λ°©μμ λ‘κΉ
λ‘μ§μ ν΅μ¬ λ©μλ λ‘μ§κ³Ό λΆλ¦¬νμ¬ μ½λ κ°λ
μ±κ³Ό μ μ§ κ΄λ¦¬μ±μ ν₯μμν΅λλ€.
λ°μ½λ μ΄ν° μ ν
JavaScriptμλ λ€ κ°μ§ μ νμ λ°μ½λ μ΄ν°κ° μμΌλ©°, κ°κ° κ³ μ ν λͺ©μ μ μνν©λλ€.
- ν΄λμ€ λ°μ½λ μ΄ν°: μ΄λ¬ν λ°μ½λ μ΄ν°λ ν΄λμ€ μμ±μλ₯Ό μμ ν©λλ€. μ μμ±, λ©μλλ₯Ό μΆκ°νκ±°λ κΈ°μ‘΄ μμ±μ μμ νλ λ° μ¬μ©ν μ μμ΅λλ€.
- λ©μλ λ°μ½λ μ΄ν°: μ΄λ¬ν λ°μ½λ μ΄ν°λ λ©μλμ λμμ μμ ν©λλ€. λ©μλ μ€ν μ νμ λ‘κΉ , μ ν¨μ± κ²μ¬ λλ κΆν λΆμ¬ λ‘μ§μ μΆκ°νλ λ° μ¬μ©ν μ μμ΅λλ€.
- μμ± λ°μ½λ μ΄ν°: μ΄λ¬ν λ°μ½λ μ΄ν°λ μμ±μ κΈ°μ μ(descriptor)λ₯Ό μμ ν©λλ€. λ°μ΄ν° λ°μΈλ©, μ ν¨μ± κ²μ¬ λλ μ§μ° μ΄κΈ°νλ₯Ό ꡬννλ λ° μ¬μ©ν μ μμ΅λλ€.
- λ§€κ°λ³μ λ°μ½λ μ΄ν°: μ΄λ¬ν λ°μ½λ μ΄ν°λ λ©μλμ λ§€κ°λ³μμ λν λ©νλ°μ΄ν°λ₯Ό μ 곡ν©λλ€. λ§€κ°λ³μ μ ν λλ κ°μ λ°λΌ μμ‘΄μ± μ£Όμ λλ μ ν¨μ± κ²μ¬ λ‘μ§μ ꡬννλ λ° μ¬μ©ν μ μμ΅λλ€.
κΈ°λ³Έ λ°μ½λ μ΄ν° ꡬ문
λ°μ½λ μ΄ν°λ κΎΈλ©°μ§ μμμ μ νμ λ°λΌ νλ, λ λλ μΈ κ°μ μΈμλ₯Ό λ°λ ν¨μμ λλ€.
- ν΄λμ€ λ°μ½λ μ΄ν°: ν΄λμ€ μμ±μλ₯Ό μΈμλ‘ λ°μ΅λλ€.
- λ©μλ λ°μ½λ μ΄ν°: μΈ κ°μ μΈμ, μ¦ λμ κ°μ²΄(μ μ λ©€λ²μ κ²½μ° μμ±μ ν¨μ λλ μΈμ€ν΄μ€ λ©€λ²μ κ²½μ° ν΄λμ€μ νλ‘ν νμ ), λ©€λ² μ΄λ¦ λ° λ©€λ²μ λν μμ± κΈ°μ μλ₯Ό λ°μ΅λλ€.
- μμ± λ°μ½λ μ΄ν°: λ κ°μ μΈμ, μ¦ λμ κ°μ²΄ λ° μμ± μ΄λ¦μ λ°μ΅λλ€.
- λ§€κ°λ³μ λ°μ½λ μ΄ν°: μΈ κ°μ μΈμ, μ¦ λμ κ°μ²΄, λ©μλ μ΄λ¦ λ° λ©μλμ λ§€κ°λ³μ λͺ©λ‘μμ λ§€κ°λ³μμ μΈλ±μ€λ₯Ό λ°μ΅λλ€.
λ€μμ κ°λ¨ν ν΄λμ€ λ°μ½λ μ΄ν°μ μμ λλ€.
function sealed(constructor: Function) {
Object.seal(constructor);
Object.seal(constructor.prototype);
}
@sealed
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
μ΄ μμμ @sealed λ°μ½λ μ΄ν°λ Greeter ν΄λμ€μ μ μ©λ©λλ€. sealed ν¨μλ μμ±μμ νλ‘ν νμ
μ λͺ¨λ λκ²°νμ¬ μΆκ° μμ μ λ°©μ§ν©λλ€. μ΄λ νΉμ ν΄λμ€μ λΆλ³μ±μ 보μ₯νλ λ° μ μ©ν μ μμ΅λλ€.
λ©νλ°μ΄ν° 리νλ μ μ ν
λ©νλ°μ΄ν° 리νλ μ
μ λ°νμμ ν΄λμ€, λ©μλ, μμ± λ° λ§€κ°λ³μμ κ΄λ ¨λ λ©νλ°μ΄ν°μ μ‘μΈμ€νλ λ°©λ²μ μ 곡ν©λλ€. μ΄λ₯Ό ν΅ν΄ μμ‘΄μ± μ£Όμ
, μ§λ ¬ν λ° μ ν¨μ± κ²μ¬μ κ°μ κ°λ ₯ν κΈ°λ₯μ ꡬνν μ μμ΅λλ€. JavaScript μ체λ‘λ Java λλ C#κ³Ό κ°μ μΈμ΄μ λμΌν λ°©μμΌλ‘ 리νλ μ
μ κΈ°λ³Έμ μΌλ‘ μ§μνμ§ μμ΅λλ€. κ·Έλ¬λ reflect-metadataμ κ°μ λΌμ΄λΈλ¬λ¦¬λ μ΄λ¬ν κΈ°λ₯μ μ 곡ν©λλ€.
Ron Bucktonμ΄ κ°λ°ν reflect-metadata λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νλ©΄ λ°μ½λ μ΄ν°λ₯Ό μ¬μ©νμ¬ ν΄λμ€μ ν΄λΉ λ©€λ²μ λ©νλ°μ΄ν°λ₯Ό μ°κ²°ν λ€μ λ°νμμ μ΄ λ©νλ°μ΄ν°λ₯Ό κ²μν μ μμ΅λλ€. μ΄λ₯Ό ν΅ν΄ λ μ μ°νκ³ κ΅¬μ± κ°λ₯ν μ ν리μΌμ΄μ
μ ꡬμΆν μ μμ΅λλ€.
reflect-metadata μ€μΉ λ° κ°μ Έμ€κΈ°
reflect-metadataλ₯Ό μ¬μ©νλ €λ©΄ λ¨Όμ npm λλ yarnμ μ¬μ©νμ¬ μ€μΉν΄μΌ ν©λλ€.
npm install reflect-metadata --save
λλ yarnμ μ¬μ©νμ¬:
yarn add reflect-metadata
κ·Έλ° λ€μ νλ‘μ νΈλ‘ κ°μ ΈμμΌ ν©λλ€. TypeScriptμμλ λ©μΈ νμΌ(μ: index.ts λλ app.ts)μ 맨 μμ λ€μ μ€μ μΆκ°ν μ μμ΅λλ€.
import 'reflect-metadata';
μ΄ κ°μ Έμ€κΈ° λ¬Έμ λ°μ½λ μ΄ν° λ° λ©νλ°μ΄ν° 리νλ μ
μμ μ¬μ©νλ νμν Reflect APIλ₯Ό ν΄λ¦¬ννλ―λ‘ μ€μν©λλ€. μ΄ κ°μ Έμ€κΈ°λ₯Ό μμΌλ©΄ μ½λκ° μ¬λ°λ₯΄κ² μλνμ§ μμ μ μμΌλ©° λ°νμ μ€λ₯κ° λ°μν κ°λ₯μ±μ΄ λμ΅λλ€.
λ°μ½λ μ΄ν°λ₯Ό μ¬μ©ν λ©νλ°μ΄ν° μ°κ²°
reflect-metadata λΌμ΄λΈλ¬λ¦¬λ κ°μ²΄μ λ©νλ°μ΄ν°λ₯Ό μ°κ²°νκΈ° μν΄ Reflect.defineMetadata ν¨μλ₯Ό μ 곡ν©λλ€. κ·Έλ¬λ λ°μ½λ μ΄ν°λ₯Ό μ¬μ©νμ¬ λ©νλ°μ΄ν°λ₯Ό μ μνλ κ²μ΄ λ μΌλ°μ μ΄κ³ νΈλ¦¬ν©λλ€. Reflect.metadata λ°μ½λ μ΄ν° ν©ν 리λ λ°μ½λ μ΄ν°λ₯Ό μ¬μ©νμ¬ λ©νλ°μ΄ν°λ₯Ό μ μνλ κ°κ²°ν λ°©λ²μ μ 곡ν©λλ€.
μμ:
import 'reflect-metadata';
const formatMetadataKey = Symbol("format");
function format(formatString: string) {
return Reflect.metadata(formatMetadataKey, formatString);
}
function getFormat(target: any, propertyKey: string) {
return Reflect.getMetadata(formatMetadataKey, target, propertyKey);
}
class Example {
@format("Hello, %s")
greeting: string = "World";
greet() {
let formatString = getFormat(this, "greeting");
return formatString.replace("%s", this.greeting);
}
}
let example = new Example();
console.log(example.greet()); // μΆλ ₯: Hello, World
μ΄ μμμ @format λ°μ½λ μ΄ν°λ νμ λ¬Έμμ΄ "Hello, %s"λ₯Ό Example ν΄λμ€μ greeting μμ±κ³Ό μ°κ²°νλ λ° μ¬μ©λ©λλ€. getFormat ν¨μλ Reflect.getMetadataλ₯Ό μ¬μ©νμ¬ λ°νμμ μ΄ λ©νλ°μ΄ν°λ₯Ό κ²μν©λλ€. greet λ©μλλ μ΄ λ©νλ°μ΄ν°λ₯Ό μ¬μ©νμ¬ μΈμ¬λ§ λ©μμ§λ₯Ό νμνν©λλ€.
Reflect Metadata API
reflect-metadata λΌμ΄λΈλ¬λ¦¬λ λ©νλ°μ΄ν°λ₯Ό μμ
νκΈ° μν μ¬λ¬ ν¨μλ₯Ό μ 곡ν©λλ€.
Reflect.defineMetadata(metadataKey, metadataValue, target, propertyKey?): κ°μ²΄ λλ μμ±μ λ©νλ°μ΄ν°λ₯Ό μ°κ²°ν©λλ€.Reflect.getMetadata(metadataKey, target, propertyKey?): κ°μ²΄ λλ μμ±μμ λ©νλ°μ΄ν°λ₯Ό κ²μν©λλ€.Reflect.hasMetadata(metadataKey, target, propertyKey?): κ°μ²΄ λλ μμ±μ λ©νλ°μ΄ν°κ° μλμ§ νμΈν©λλ€.Reflect.deleteMetadata(metadataKey, target, propertyKey?): κ°μ²΄ λλ μμ±μμ λ©νλ°μ΄ν°λ₯Ό μμ ν©λλ€.Reflect.getMetadataKeys(target, propertyKey?): κ°μ²΄ λλ μμ±μ μ μλ λͺ¨λ λ©νλ°μ΄ν° ν€μ λ°°μ΄μ λ°νν©λλ€.Reflect.getOwnMetadataKeys(target, propertyKey?): κ°μ²΄ λλ μμ±μ μ§μ μ μλ λͺ¨λ λ©νλ°μ΄ν° ν€μ λ°°μ΄μ λ°νν©λλ€(μμλ λ©νλ°μ΄ν° μ μΈ).
μ¬μ© μ¬λ‘ λ° μ€μ μ
λ°μ½λ μ΄ν°μ λ©νλ°μ΄ν° 리νλ μ μ νλ JavaScript κ°λ°μ μλ§μ μμ© νλ‘κ·Έλ¨μ κ°μ§κ³ μμ΅λλ€. λͺ κ°μ§ μλ λ€μκ³Ό κ°μ΅λλ€.
μμ‘΄μ± μ£Όμ
μμ‘΄μ± μ£Όμ (DI)μ ν΄λμ€ μμ²΄κ° μμ±νλ λμ ν΄λμ€μ μ’ μμ±μ μ 곡νμ¬ κ΅¬μ± μμ κ°μ λμ¨ν κ²°ν©μ μ΄μ§νλ λμμΈ ν¨ν΄μ λλ€. λ°μ½λ μ΄ν°μ λ©νλ°μ΄ν° 리νλ μ μ μ¬μ©νμ¬ JavaScriptμμ DI 컨ν μ΄λλ₯Ό ꡬνν μ μμ΅λλ€.
UserRepositoryμ μμ‘΄νλ UserServiceκ° μλ μλ리μ€λ₯Ό μκ°ν΄ λ΄
μλ€. λ°μ½λ μ΄ν°λ₯Ό μ¬μ©νμ¬ μ’
μμ±μ μ§μ νκ³ DI 컨ν
μ΄λλ₯Ό μ¬μ©νμ¬ λ°νμμ μ΄λ₯Ό ν΄κ²°ν μ μμ΅λλ€.
import 'reflect-metadata';
const Injectable = (): ClassDecorator => {
return (target: any) => {
Reflect.defineMetadata('design:paramtypes', [], target);
};
};
const Inject = (token: any): ParameterDecorator => {
return (target: any, propertyKey: string | symbol, parameterIndex: number) => {
let existingParameters: any[] = Reflect.getOwnMetadata('design:paramtypes', target, propertyKey) || [];
existingParameters[parameterIndex] = token;
Reflect.defineMetadata('design:paramtypes', existingParameters, target, propertyKey);
};
};
class UserRepository {
getUsers() {
return ['user1', 'user2'];
}
}
@Injectable()
class UserService {
private userRepository: UserRepository;
constructor(@Inject(UserRepository) userRepository: UserRepository) {
this.userRepository = userRepository;
}
getUsers() {
return this.userRepository.getUsers();
}
}
// κ°λ¨ν DI 컨ν
μ΄λ
class Container {
private static dependencies = new Map();
static register(key: any, concrete: { new(...args: any[]): T }): void {
Container.dependencies.set(key, concrete);
}
static resolve(key: any): T {
const concrete = Container.dependencies.get(key);
if (!concrete) {
throw new Error(`No binding found for ${key}`);
}
const paramtypes = Reflect.getMetadata('design:paramtypes', concrete) || [];
const dependencies = paramtypes.map((param: any) => Container.resolve(param));
return new concrete(...dependencies);
}
}
// μ’
μμ± λ±λ‘
Container.register(UserRepository, UserRepository);
Container.register(UserService, UserService);
// UserService ν΄κ²°
const userService = Container.resolve(UserService);
console.log(userService.getUsers()); // μΆλ ₯: ['user1', 'user2']
μ΄ μμμ @Injectable λ°μ½λ μ΄ν°λ μ£Όμ
κ°λ₯ν ν΄λμ€λ₯Ό νμνκ³ , @Inject λ°μ½λ μ΄ν°λ μμ±μμ μ’
μμ±μ μ§μ ν©λλ€. Container ν΄λμ€λ λ¨μν DI 컨ν
μ΄λ μν μ νλ©° λ°μ½λ μ΄ν°μ μν΄ μ μλ λ©νλ°μ΄ν°λ₯Ό κΈ°λ°μΌλ‘ μ’
μμ±μ ν΄κ²°ν©λλ€.
μ§λ ¬ν λ° μμ§λ ¬ν
λ°μ½λ μ΄ν°μ λ©νλ°μ΄ν° 리νλ μ μ κ°μ²΄μ μ§λ ¬ν λ° μμ§λ ¬ν νλ‘μΈμ€λ₯Ό μ¬μ©μ μ μνλ λ° μ¬μ©ν μ μμ΅λλ€. μ΄λ κ°μ²΄λ₯Ό JSON λλ XMLκ³Ό κ°μ λ€λ₯Έ λ°μ΄ν° νμμΌλ‘ λ§€ννκ±°λ μμ§λ ¬ν μ μ λ°μ΄ν°λ₯Ό μ ν¨μ± κ²μ¬νλ λ° μ μ©ν μ μμ΅λλ€.
νΉμ μμ±μ μ μΈνκ±°λ μ΄λ¦μ λ°κΎΈκ³ μΆμ§λ§ ν΄λμ€λ₯Ό JSONμΌλ‘ μ§λ ¬ννλ €λ μλ리μ€λ₯Ό μκ°ν΄ λ΄ μλ€. λ°μ½λ μ΄ν°λ₯Ό μ¬μ©νμ¬ μ§λ ¬ν κ·μΉμ μ§μ ν λ€μ λ©νλ°μ΄ν°λ₯Ό μ¬μ©νμ¬ μ§λ ¬νλ₯Ό μνν μ μμ΅λλ€.
import 'reflect-metadata';
const Exclude = (): PropertyDecorator => {
return (target: any, propertyKey: string | symbol) => {
Reflect.defineMetadata('serialize:exclude', true, target, propertyKey);
};
};
const Rename = (newName: string): PropertyDecorator => {
return (target: any, propertyKey: string | symbol) => {
Reflect.defineMetadata('serialize:rename', newName, target, propertyKey);
};
};
class User {
@Exclude()
id: number;
@Rename('fullName')
name: string;
email: string;
constructor(id: number, name: string, email: string) {
this.id = id;
this.name = name;
this.email = email;
}
}
function serialize(obj: any): string {
const serialized: any = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
const exclude = Reflect.getMetadata('serialize:exclude', obj, key);
if (exclude) {
continue;
}
const rename = Reflect.getMetadata('serialize:rename', obj, key);
const newKey = rename || key;
serialized[newKey] = obj[key];
}
}
return JSON.stringify(serialized);
}
const user = new User(1, 'John Doe', 'john.doe@example.com');
const serializedUser = serialize(user);
console.log(serializedUser); // μΆλ ₯: {"fullName":"John Doe","email":"john.doe@example.com"}
μ΄ μμμ @Exclude λ°μ½λ μ΄ν°λ id μμ±μ μ§λ ¬νμμ μ μΈλ¨μΌλ‘ νμνκ³ , @Rename λ°μ½λ μ΄ν°λ name μμ±μ fullNameμΌλ‘ μ΄λ¦μ λ°κΏλλ€. serialize ν¨μλ λ©νλ°μ΄ν°λ₯Ό μ¬μ©νμ¬ μ μλ κ·μΉμ λ°λΌ μ§λ ¬νλ₯Ό μνν©λλ€.
μ ν¨μ± κ²μ¬
λ°μ½λ μ΄ν°μ λ©νλ°μ΄ν° 리νλ μ μ ν΄λμ€μ μμ±μ μ ν¨μ± κ²μ¬ λ‘μ§μ ꡬννλ λ° μ¬μ©ν μ μμ΅λλ€. μ΄λ λ°μ΄ν°κ° μ²λ¦¬λκ±°λ μ μ₯λκΈ° μ μ νΉμ κΈ°μ€μ μΆ©μ‘±νλμ§ νμΈνλ λ° μ μ©ν μ μμ΅λλ€.
μμ±μ΄ λΉμ΄ μμ§ μκ±°λ νΉμ μ κ·μκ³Ό μΌμΉνλμ§ νμΈνλ €λ μλ리μ€λ₯Ό μκ°ν΄ λ΄ μλ€. λ°μ½λ μ΄ν°λ₯Ό μ¬μ©νμ¬ μ ν¨μ± κ²μ¬ κ·μΉμ μ§μ ν λ€μ λ©νλ°μ΄ν°λ₯Ό μ¬μ©νμ¬ μ ν¨μ± κ²μ¬λ₯Ό μνν μ μμ΅λλ€.
import 'reflect-metadata';
const Required = (): PropertyDecorator => {
return (target: any, propertyKey: string | symbol) => {
Reflect.defineMetadata('validate:required', true, target, propertyKey);
};
};
const Pattern = (regex: RegExp): PropertyDecorator => {
return (target: any, propertyKey: string | symbol) => {
Reflect.defineMetadata('validate:pattern', regex, target, propertyKey);
};
};
class Product {
@Required()
name: string;
@Pattern(/^\d+$/)
price: string;
constructor(name: string, price: string) {
this.name = name;
this.price = price;
}
}
function validate(obj: any): string[] {
const errors: string[] = [];
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
const required = Reflect.getMetadata('validate:required', obj, key);
if (required && !obj[key]) {
errors.push(`${key} is required`);
}
const pattern = Reflect.getMetadata('validate:pattern', obj, key);
if (pattern && !pattern.test(obj[key])) {
errors.push(`${key} must match ${pattern}`);
}
}
}
return errors;
}
const product = new Product('', 'abc');
const errors = validate(product);
console.log(errors); // μΆλ ₯: ["name is required", "price must match /^\\d+$/"]
μ΄ μμμ @Required λ°μ½λ μ΄ν°λ name μμ±μ νμ νλͺ©μΌλ‘ νμνκ³ , @Pattern λ°μ½λ μ΄ν°λ price μμ±μ΄ μΌμΉν΄μΌ νλ μ κ·μμ μ§μ ν©λλ€. validate ν¨μλ λ©νλ°μ΄ν°λ₯Ό μ¬μ©νμ¬ μ ν¨μ± κ²μ¬λ₯Ό μννκ³ μ€λ₯ λ°°μ΄μ λ°νν©λλ€.
AOP (Aspect-Oriented Programming)
AOPλ κ΅μ°¨ κ΄μ¬μ¬ λΆλ¦¬λ₯Ό νμ©νμ¬ λͺ¨λμ±μ λμ΄λ κ²μ λͺ©νλ‘ νλ νλ‘κ·Έλλ° ν¨λ¬λ€μμ λλ€. λ°μ½λ μ΄ν°λ μμ°μ€λ½κ² AOP μλ리μ€μ μ ν©ν©λλ€. μλ₯Ό λ€μ΄, λ‘κΉ , κ°μ¬ λ° λ³΄μ κ²μ¬λ λ°μ½λ μ΄ν°λ‘ ꡬννκ³ ν΅μ¬ λ©μλ λ‘μ§μ μμ νμ§ μκ³ λ©μλμ μ μ©ν μ μμ΅λλ€.
μ: λ°μ½λ μ΄ν°λ₯Ό μ¬μ©νμ¬ λ‘κΉ μΈ‘λ©΄ ꡬν.
import 'reflect-metadata';
function LogMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`Entering method: ${propertyKey} with arguments: ${JSON.stringify(args)}`);
const result = originalMethod.apply(this, args);
console.log(`Exiting method: ${propertyKey} with result: ${result}`);
return result;
};
return descriptor;
}
class Calculator {
@LogMethod
add(a: number, b: number): number {
return a + b;
}
@LogMethod
subtract(a: number, b: number): number {
return a - b;
}
}
const calculator = new Calculator();
calculator.add(5, 3);
calculator.subtract(10, 2);
// μΆλ ₯:
Entering method: add with arguments: [5,3]
Exiting method: add with result: 8
Entering method: subtract with arguments: [10,2]
Exiting method: subtract with result: 8
μ΄ μ½λλ add λ° subtract λ©μλμ μ§μ
λ° μ’
λ£ μ§μ μ κΈ°λ‘νμ¬ λ‘κΉ
κ΄μ¬μ¬λ₯Ό κ³μ°κΈ°μ ν΅μ¬ κΈ°λ₯κ³Ό ν¨κ³Όμ μΌλ‘ λΆλ¦¬ν©λλ€.
λ°μ½λ μ΄ν° λ° λ©νλ°μ΄ν° 리νλ μ μ¬μ©μ μ΄μ
JavaScriptμμ λ°μ½λ μ΄ν°μ λ©νλ°μ΄ν° 리νλ μ μ μ¬μ©νλ©΄ λ€μκ³Ό κ°μ μ¬λ¬ κ°μ§ μ΄μ μ μ»μ μ μμ΅λλ€.
- μ½λ κ°λ μ± ν₯μ: λ°μ½λ μ΄ν°λ ν΄λμ€μ ν΄λΉ λ©€λ²μ λμμ μμ νκ±°λ νμ₯νλ κ°κ²°νκ³ μ μΈμ μΈ λ°©λ²μ μ 곡νμ¬ μ½λλ₯Ό λ μ½κ² μ½κ³ μ΄ν΄ν μ μμ΅λλ€.
- λͺ¨λμ± μ¦λ: λ°μ½λ μ΄ν°λ κ΄μ¬μ¬ λΆλ¦¬λ₯Ό μ΄μ§νμ¬ κ΅μ°¨ κ΄μ¬μ¬λ₯Ό 격리νκ³ μ½λ μ€λ³΅μ νΌν μ μμ΅λλ€.
- μ μ§ κ΄λ¦¬μ± ν₯μ: κ΄μ¬μ¬λ₯Ό λΆλ¦¬νκ³ μ½λ μ€λ³΅μ μ€μμΌλ‘μ¨ λ°μ½λ μ΄ν°λ₯Ό μ¬μ©νλ©΄ μ½λλ₯Ό λ μ½κ² μ μ§ κ΄λ¦¬νκ³ μ λ°μ΄νΈν μ μμ΅λλ€.
- λ ν° μ μ°μ±: λ©νλ°μ΄ν° 리νλ μ μ μ¬μ©νλ©΄ λ°νμμ λ©νλ°μ΄ν°μ μ‘μΈμ€ν μ μμΌλ―λ‘ λ μ μ°νκ³ κ΅¬μ± κ°λ₯ν μ ν리μΌμ΄μ μ ꡬμΆν μ μμ΅λλ€.
- AOP μ§μ: λ°μ½λ μ΄ν°λ ν΅μ¬ λ‘μ§μ μμ νμ§ μκ³ λ λ©μλμ μΈ‘λ©΄μ μ μ©ν μ μλλ‘ νμ¬ AOPλ₯Ό μ©μ΄νκ² ν©λλ€.
κ³Όμ λ° κ³ λ € μ¬ν
λ°μ½λ μ΄ν°μ λ©νλ°μ΄ν° 리νλ μ μ μλ§μ μ΄μ μ μ 곡νμ§λ§ λͺ μ¬ν΄μΌ ν λͺ κ°μ§ κ³Όμ μ κ³ λ € μ¬νλ μμ΅λλ€.
- μ±λ₯ μ€λ²ν€λ: λ©νλ°μ΄ν° 리νλ μ μ νΉν κ΄λ²μνκ² μ¬μ©λλ κ²½μ° μ±λ₯ μ€λ²ν€λλ₯Ό μ½κ° λμ ν μ μμ΅λλ€.
- 볡μ‘μ±: λ°μ½λ μ΄ν°μ λ©νλ°μ΄ν° 리νλ μ
μ μ΄ν΄νκ³ μ¬μ©νλ λ°λ JavaScriptμ
reflect-metadataλΌμ΄λΈλ¬λ¦¬μ λν λ κΉμ μ΄ν΄κ° νμν©λλ€. - λλ²κΉ : λ°μ½λ μ΄ν°μ λ©νλ°μ΄ν° 리νλ μ μ μ¬μ©νλ μ½λ λλ²κΉ μ κΈ°μ‘΄ μ½λ λλ²κΉ λ³΄λ€ λ μ΄λ €μΈ μ μμ΅λλ€.
- νΈνμ±: λ°μ½λ μ΄ν°λ μ¬μ ν μ€ν μ΄μ§ 2 ECMAScript μ μμ΄λ©°, λ€μν JavaScript νκ²½μμ ꡬνμ΄ λ€λ₯Ό μ μμ΅λλ€. TypeScriptλ νλ₯ν μ§μμ μ 곡νμ§λ§ λ°νμ ν΄λ¦¬νμ΄ νμμ μμ κΈ°μ΅νμμμ€.
λͺ¨λ² μ¬λ‘
λ°μ½λ μ΄ν°μ λ©νλ°μ΄ν° 리νλ μ μ ν¨κ³Όμ μΌλ‘ μ¬μ©νλ €λ©΄ λ€μ λͺ¨λ² μ¬λ‘λ₯Ό κ³ λ €νμμμ€.
- λ°μ½λ μ΄ν°λ μ μ€νκ² μ¬μ©: μ½λ κ°λ μ±, λͺ¨λμ± λλ μ μ§ κ΄λ¦¬μ± μΈ‘λ©΄μμ λͺ νν μ΄μ μ μ 곡νλ κ²½μ°μλ§ λ°μ½λ μ΄ν°λ₯Ό μ¬μ©νμμμ€. λ°μ½λ μ΄ν°λ₯Ό κ³Όλνκ² μ¬μ©νλ©΄ μ½λκ° λ 볡μ‘ν΄μ§κ³ λλ²κΉ νκΈ° μ΄λ €μμ§ μ μμΌλ―λ‘ νΌνμμμ€.
- λ°μ½λ μ΄ν°λ κ°λ¨νκ² μ μ§: λ°μ½λ μ΄ν°λ λ¨μΌ μ± μμ μ§μ€νλλ‘ ν©λλ€. μ¬λ¬ μμ μ μννλ 볡μ‘ν λ°μ½λ μ΄ν°λ₯Ό λ§λ€μ§ λ§μμμ€.
- λ°μ½λ μ΄ν° λ¬Έμν: κ° λ°μ½λ μ΄ν°μ λͺ©μ κ³Ό μ¬μ©λ²μ λͺ ννκ² λ¬Έμννμμμ€. μ΄λ κ² νλ©΄ λ€λ₯Έ κ°λ°μκ° μ½λλ₯Ό λ μ½κ² μ΄ν΄νκ³ μ¬μ©ν μ μμ΅λλ€.
- λ°μ½λ μ΄ν° μ² μ ν ν μ€νΈ: λ°μ½λ μ΄ν°κ° μ¬λ°λ₯΄κ² μλνκ³ μμμΉ λͺ»ν λΆμμ©μ μΌμΌν€μ§ μλμ§ μ² μ ν ν μ€νΈνμμμ€.
- μΌκ΄λ λͺ
λͺ
κ·μΉ μ¬μ©: μ½λ κ°λ
μ±μ ν₯μμν€κΈ° μν΄ λ°μ½λ μ΄ν°μ λν μΌκ΄λ λͺ
λͺ
κ·μΉμ μ±ννμμμ€. μλ₯Ό λ€μ΄, λͺ¨λ λ°μ½λ μ΄ν° μ΄λ¦ μμ
@λ₯Ό λΆμΌ μ μμ΅λλ€.
λμ
λ°μ½λ μ΄ν°λ ν΄λμ€μ λ©μλμ κΈ°λ₯μ μΆκ°νλ κ°λ ₯ν λ©μ»€λμ¦μ μ 곡νμ§λ§, λ°μ½λ μ΄ν°λ₯Ό μ¬μ©ν μ μκ±°λ μ ν©νμ§ μμ μν©μμλ μ¬μ©ν μ μλ λμμ μΈ μ κ·Ό λ°©μμ΄ μμ΅λλ€.
κ³ μ°¨ ν¨μ
κ³ μ°¨ ν¨μ(HOF)λ λ€λ₯Έ ν¨μλ₯Ό μΈμλ‘ λ°κ±°λ ν¨μλ₯Ό κ²°κ³Όλ‘ λ°ννλ ν¨μμ λλ€. HOFλ λ‘κΉ , μ ν¨μ± κ²μ¬ λ° κΆν λΆμ¬μ κ°μ λ°μ½λ μ΄ν°μ λμΌν ν¨ν΄μ λ§μ΄ ꡬννλ λ° μ¬μ©ν μ μμ΅λλ€.
λ―Ήμ€μΈ
λ―Ήμ€μΈμ λ€λ₯Έ ν΄λμ€μμ μ‘°ν©μ ν΅ν΄ ν΄λμ€μ κΈ°λ₯μ μΆκ°νλ λ°©λ²μ λλ€. λ―Ήμ€μΈμ μ¬λ¬ ν΄λμ€ κ°μ μ½λλ₯Ό 곡μ νκ³ μ½λ μ€λ³΅μ νΌνλ λ° μ¬μ©ν μ μμ΅λλ€.
λͺ½ν€ ν¨μΉ
λͺ½ν€ ν¨μΉμ λ°νμμ κΈ°μ‘΄ μ½λμ λμμ μμ νλ κ΄νμ λλ€. λͺ½ν€ ν¨μΉμ μ¬μ©νμ¬ μμ€ μ½λλ₯Ό μμ νμ§ μκ³ ν΄λμ€μ λ©μλμ κΈ°λ₯μ μΆκ°ν μ μμ΅λλ€. κ·Έλ¬λ λͺ½ν€ ν¨μΉμ μνν μ μμΌλ©° μμμΉ λͺ»ν λΆμμ©μ μΌμΌν€κ³ μ½λλ₯Ό μ μ§ κ΄λ¦¬νκΈ° μ΄λ ΅κ² λ§λ€ μ μμΌλ―λ‘ μ£Όμν΄μ μ¬μ©ν΄μΌ ν©λλ€.
κ²°λ‘
JavaScript λ°μ½λ μ΄ν°λ λ©νλ°μ΄ν° 리νλ μ κ³Ό κ²°ν©νμ¬ μ½λ λͺ¨λμ±, μ μ§ κ΄λ¦¬μ± λ° μ μ°μ±μ ν₯μμν€λ κ°λ ₯ν λꡬ μΈνΈλ₯Ό μ 곡ν©λλ€. λ°νμ λ©νλ°μ΄ν° μ‘μΈμ€λ₯Ό κ°λ₯νκ² ν¨μΌλ‘μ¨ μμ‘΄μ± μ£Όμ , μ§λ ¬ν, μ ν¨μ± κ²μ¬ λ° AOPμ κ°μ κ³ κΈ κΈ°λ₯μ μ κΈ ν΄μ ν©λλ€. μ±λ₯ μ€λ²ν€λ λ° λ³΅μ‘μ±κ³Ό κ°μ κ³ λ €ν΄μΌ ν κ³Όμ κ° μμ§λ§, λ°μ½λ μ΄ν°μ λ©νλ°μ΄ν° 리νλ μ μ¬μ©μ μ΄μ μ μ’ μ’ λ¨μ λ³΄λ€ ν½λλ€. λͺ¨λ² μ¬λ‘λ₯Ό λ°λ₯΄κ³ λμμ μ΄ν΄ν¨μΌλ‘μ¨ κ°λ°μλ μ΄λ¬ν κΈ°μ μ ν¨κ³Όμ μΌλ‘ νμ©νμ¬ λ κ°λ ₯νκ³ νμ₯ κ°λ₯ν JavaScript μ ν리μΌμ΄μ μ ꡬμΆν μ μμ΅λλ€. JavaScriptκ° κ³μ λ°μ ν¨μ λ°λΌ λ°μ½λ μ΄ν°μ λ©νλ°μ΄ν° 리νλ μ μ νλ μΉ κ°λ°μμ 볡μ‘μ±μ κ΄λ¦¬νκ³ μ½λ μ¬μ¬μ©μ±μ μ΄μ§νλ λ° μ μ λ μ€μν΄μ§ κ°λ₯μ±μ΄ λμ΅λλ€.
μ΄ κΈ°μ¬λ JavaScript λ°μ½λ μ΄ν°, λ©νλ°μ΄ν° λ° λ¦¬νλ μ μ λν ν¬κ΄μ μΈ κ°μλ₯Ό μ 곡νλ©°, ꡬ문, μ¬μ© μ¬λ‘ λ° λͺ¨λ² μ¬λ‘λ₯Ό λ€λ£Ήλλ€. μ΄λ¬ν κ°λ μ μ΄ν΄ν¨μΌλ‘μ¨ κ°λ°μλ JavaScriptμ μ 체 μ μ¬λ ₯μ νμ©νκ³ λ κ°λ ₯νκ³ μ μ§ κ΄λ¦¬ κ°λ₯ν μ ν리μΌμ΄μ μ ꡬμΆν μ μμ΅λλ€.
μ΄λ¬ν κΈ°μ μ μ±νν¨μΌλ‘μ¨ μ μΈκ³ κ°λ°μλ λ λͺ¨λνλκ³ μ μ§ κ΄λ¦¬ κ°λ₯νλ©° νμ₯ κ°λ₯ν JavaScript μνκ³μ κΈ°μ¬ν μ μμ΅λλ€.